package com.zyl.blog.common.utils.Extreme;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 日志记录工具类，提供多级别日志记录和异常堆栈跟踪功能
 *
 * <p>本工具类实现以下特性：
 * <ul>
 *   <li>自动获取调用方类名作为Logger名称</li>
 *   <li>支持参数化日志模板（类似SLF4J的{}占位符语法）</li>
 *   <li>提供异常与日志信息的关联记录</li>
 *   <li>线程安全的静态方法设计</li>
 * </ul>
 * @version v1.0
 * @ProjectName: Personal_Blog
 * @Package: com.zyl.common.utils.Extreme
 * @ClassName: LogUtil
 * @Author FinalFantasy
 * @Date 2025/2/14-16:47
 */
public final class LogUtil {

    /**
     * 私有构造函数防止实例化
     */
    private LogUtil() {
        throw new AssertionError("工具类禁止实例化");
    }

    /**
     * 记录INFO级别日志
     *
     * @param format 日志消息模板，使用%s作为占位符（兼容SLF4J的{}风格）
     * @param args   动态参数列表，按顺序替换模板中的占位符
     *
     * @example
     * LogUtil.info("用户[%s]登录成功", userId);
     */
    public static void info(String format, Object... args) {
        log(LogLevel.INFO, format, args, null);
    }

    /**
     * 记录TRACE级别日志
     *
     * @param format 调试消息模板，使用%s作为占位符（兼容SLF4J的{}风格）
     * @param args   动态参数列表，按顺序替换模板中的占位符
     *
     * @example
     * LogUtil.TRACE("用户[%s]登录成功", userId);
     */
    public static void trace(String format, Object... args) {
        log(LogLevel.TRACE, format, args, null);
    }

    /**
     * 记录WARN级别日志
     *
     * @param format 日志消息模板，使用%s作为占位符（兼容SLF4J的{}风格）
     * @param args   动态参数列表，按顺序替换模板中的占位符
     *
     * @example
     * LogUtil.warn("文件上传失败", file.getName());
     */
    public static void warn(String format, Object... args) {
        log(LogLevel.WARN, format, args, null);
    }

    /**
     * 记录DEBUG级别日志
     *
     * @param format 日志消息模板，使用%s作为占位符（兼容SLF4J的{}风格）
     * @param args   动态参数列表，按顺序替换模板中的占位符
     *
     * @example
     * LogUtil.debug("文件上传失败", file.getName());
     */
    public static void debug(String format, Object... args) {
        log(LogLevel.DEBUG, format, args, null);
    }

    /**
     * 记录ERROR级别日志（带异常堆栈）
     *
     * @param format    日志消息模板
     * @param throwable 关联的异常对象
     * @param args      动态参数列表
     *
     * @example
     * LogUtil.error("文件上传失败", ex, file.getName());
     */
    public static void error(String format, Throwable throwable, Object... args) {
        log(LogLevel.ERROR, format, args, throwable);
    }

    /**
     * 通用日志记录方法（供内部使用）
     *
     * @param level     日志级别，参见{@link LogLevel}
     * @param format    消息模板（使用%s占位符）
     * @param args      动态参数数组
     * @param throwable 关联的Throwable对象，可为null
     *
     * @throws IllegalArgumentException 如果传入的日志级别不合法
     */
    private static void log(LogLevel level, String format, Object[] args, Throwable throwable) {
        Logger logger = LoggerFactory.getLogger(getCallerClass());
        String formattedMsg = String.format(format.replace("{}", "%s"), args);

        switch (level) {
            case INFO:
                logger.info(formattedMsg, throwable);
                break;
            case ERROR:
                logger.error(formattedMsg, throwable);
                break;
            case WARN:
                logger.warn(formattedMsg, throwable);
                break;
            case DEBUG:
                logger.debug(formattedMsg, throwable);
                break;
            default:
                throw new IllegalArgumentException("不支持的日志级别: " + level);
        }
    }

    /**
     * 获取调用者类名（跳过工具类本身的堆栈帧）
     *
     * @return 调用方的Class对象，用于获取正确的Logger名称
     *
     * @implNote 使用Java 9+的StackWalker API实现，需确保运行环境支持
     */
    private static Class<?> getCallerClass() {
        return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                .walk(frames -> frames.skip(2)
                        .findFirst()
                        .map(StackWalker.StackFrame::getDeclaringClass)
                        .orElseThrow(() -> new IllegalStateException("无法获取调用类信息")));

    }

    /**
     * 日志级别枚举
     */
    public enum LogLevel {
        /** 普通信息级别 */
        INFO,
        /** 警告级别 */
        WARN,
        /** 错误级别 */
        ERROR,
        /** 调试信息级别 */
        DEBUG,
        /** 调试级别 */
        TRACE
    }
}